package com.first.wchat.data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

import com.wchat.network.Actions;
import com.wchat.network.Configs;
import com.wchat.network.Controller;
import com.wchat.network.device.BroadCastTarget;
import com.wchat.network.device.Device;
import com.wchat.network.device.DeviceContext;
import com.wchat.network.device.Group;
import com.wchat.network.device.SendTarget;
import com.wchat.network.message.Message;
import com.wchat.network.message.TextMessage;
import com.wchat.network.message.file.FileMessage;
import com.wchat.network.message.file.FileReadyMessage;
import com.wchat.network.message.file.ImageMessage;
import com.wchat.util.Util;

public class MSGDataManager {

	private static MSGDataManager mInstance;
	private Context mCtx;
	private HashMap<SendTarget,ArrayList<MessageData>> mMessageMap = new HashMap<SendTarget,ArrayList<MessageData>>();
	private Vector<WchatListener> mListeners =new Vector<WchatListener>();
	private ArrayList<WeakReference<Bitmap>> imagesCache = new ArrayList<WeakReference<Bitmap>>();

	BroadcastReceiver receiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, final Intent intent) {
			String action = intent.getAction();
			if (Actions.ACTION_RECEIVE_MESSAGE.equals(action)) {
				Message message = (Message) intent.getSerializableExtra("message");
				Controller.getInstance().handle(message);
				byte type = message.getType();
				
				if(type == Message.TYPE_TEXT)
				{
					TextMessage textMessage = (TextMessage) message;
					SendTarget target = null;
					long groupID = textMessage.getGroup();
					
					target = Controller.getInstance().getDeviceContext().getMessageDevice(textMessage);
					if(groupID == Message.GROUP_BROADCAST)
					{
						addMessage(BroadCastTarget.getInstance(),target,textMessage.getText(),null);
					}else if(groupID == Message.GROUP_ONE2ONE)
					{
						addMessage(target,target,textMessage.getText(),null);
					}
					else
					{
						SendTarget group = Controller.getInstance().getDeviceContext().getGroupById(groupID);
						addMessage(group,target,textMessage.getText(),null);
					}
					
				}
				
				else if(type == Message.TYPE_IMAGE)
				{
					
				}
			} else if (Actions.ACTION_DEVICE_FOUND.equals(action)) {
				Device device = (Device) intent.getSerializableExtra("device");
				Configs.i("device found: " + device);
				
				mInstance.notify(device,true);

			} else if (Actions.ACTION_DEVICE_UPDATED.equals(action)) {
				Device device = (Device) intent.getSerializableExtra("device");
				Configs.i("device update: " + device);
				mInstance.notify(device,true);

			} else if (Actions.ACTION_DEVICE_LOST.equals(action)) {
				Device device = (Device) intent.getSerializableExtra("device");
				Configs.i("device lost: " + device);
				mInstance.notify(device,false);

			} else if (Actions.ACTION_GROUP_FOUND.equals(action)) {
				Group group = (Group) intent.getSerializableExtra("group");
				Configs.i("group found: " + group);
				mInstance.notify(group,true);

			} else if (Actions.ACTION_GROUP_UPDATED.equals(action)) {
				Group group = (Group) intent.getSerializableExtra("group");
				Configs.i("group updated: " + group);
				mInstance.notify(group,true);

			} else if (Actions.ACTION_GROUP_REMOVED.equals(action)) {
				Group group = (Group) intent.getSerializableExtra("group");
				Configs.i("group updated: " + group);
				mInstance.notify(group,false);

			} else if (Actions.ACTION_FILE_TRANSFER_START.equals(action)) {
				Toast.makeText(context, action + ": ", Toast.LENGTH_SHORT).show();
			} else if (Actions.ACTION_FILE_TRANSFER_PROGRESS.equals(action)) {
				Toast.makeText(context, action + ": ", Toast.LENGTH_SHORT).show();
			} else if (Actions.ACTION_FILE_TRANSFER_SUCCESS.equals(action)) {
				Toast.makeText(context, action + ": ", Toast.LENGTH_SHORT).show();
				final File file = (File) intent.getSerializableExtra("file");
				final Message imageMessage = (Message) intent.getSerializableExtra("message");
				final int type = imageMessage.getType();
				Handler handler = new Handler();
				handler.post(new Runnable()
				{

					@Override
					public void run() {
						
						if (type == Message.TYPE_IMAGE && file != null) {
							SendTarget target = null;
							
							target = Controller.getInstance().getDeviceContext().getMessageDevice(imageMessage);
							if(target== null ||  target.equals(Controller.getInstance().getDeviceContext().getLocal()))
								return;
							long groupID =imageMessage.getGroup();
							Bitmap thumbnail = Util.getScaleBitmap(file);
							if(groupID == Message.GROUP_BROADCAST)
							{
								addMessage(BroadCastTarget.getInstance(),target,thumbnail,file.getAbsolutePath());
							}else if(groupID == Message.GROUP_ONE2ONE)
							{
								addMessage(target,target,thumbnail,file.getAbsolutePath());
							}
							else
							{
								SendTarget group = Controller.getInstance().getDeviceContext().getGroupById(groupID);
								addMessage(group,target,thumbnail,file.getAbsolutePath());
							}
						}
					}
					
				});
				
				

			} else if (Actions.ACTION_FILE_TRANSFER_CANCELLED.equals(action)) {
				Toast.makeText(context, action + ": ", Toast.LENGTH_SHORT).show();
			} else if (Actions.ACTION_FILE_TRANSFER_FAILED.equals(action)) {
				Toast.makeText(context, action + ": ", Toast.LENGTH_SHORT).show();
			}

		}
	};
	
	

	
	public class MessageData
	{
		SendTarget key;
		SendTarget device;
		Object message;
		boolean isText;
		public MessageData(SendTarget d, Object o)
		{
			device = d;
			message = o;
			isText = true;
		}
		
		public MessageData(SendTarget g,SendTarget d, Object o)
		{
			key = g;
			device = d;
			message = o;
			isText = true;
		}
		
		public SendTarget getKey()
		{
			return key;
		}
		
		public SendTarget getDevice()
		{
			return device;
		}
		
		public Object getMessage()
		{
			return message;
		}
		
		public boolean isTextType()
		{
			return isText;
		}
	}
	
	public class ImageMessageData extends MessageData
	{
		private String mPath;
		public ImageMessageData(SendTarget d, Object o,String path)
		{
			super(d,o);
			mPath = path;
			isText = false;
		}
		
		public ImageMessageData(SendTarget g,SendTarget d, Object o,String path)
		{
			super(g,d,o);
			mPath = path;
			isText = false;
		}
		
		public String getPath()
		{
			return mPath;
		}
	}
	
	
	public static MSGDataManager getInstance()
	{
		if(mInstance  == null)
			mInstance = new MSGDataManager();
		
		return mInstance;
	}
	
	public void init(Context ctx)
	{
		mCtx = ctx;
		IntentFilter filter = new IntentFilter();
		filter.addAction(Actions.ACTION_RECEIVE_MESSAGE);
		filter.addAction(Actions.ACTION_DEVICE_FOUND);
		filter.addAction(Actions.ACTION_DEVICE_UPDATED);
		filter.addAction(Actions.ACTION_DEVICE_LOST);
		filter.addAction(Actions.ACTION_GROUP_FOUND);
		filter.addAction(Actions.ACTION_GROUP_UPDATED);
		filter.addAction(Actions.ACTION_GROUP_REMOVED);
		filter.addAction(Actions.ACTION_FILE_TRANSFER_START);
		filter.addAction(Actions.ACTION_FILE_TRANSFER_PROGRESS);
		filter.addAction(Actions.ACTION_FILE_TRANSFER_SUCCESS);
		filter.addAction(Actions.ACTION_FILE_TRANSFER_CANCELLED);
		filter.addAction(Actions.ACTION_FILE_TRANSFER_FAILED);
		ctx.registerReceiver(receiver, filter);
	}
	
	
	/**
	 * release all data of manager, 
	 * this API should be called before main APP exit
	 * 
	 */
	public void release()
	{
		mListeners.clear();
		mMessageMap.clear();
		mCtx.unregisterReceiver(receiver);
		mCtx = null;
	}
	
	/**
	 * add listener to monitor all state change
	 * 
	 * @param l listener to monitor message ,device and group
	 */
	public void addListener(WchatListener l)
	{
		if(!mListeners.contains(l))
		{
			mListeners.add(l);
		}
	}
	
	/**
	 * remove the listener
	 * 
	 * @param l listener to monitor message ,device and group
	 */
	public void removeListener(WchatListener l)
	{
		if(mListeners.contains(l))
		{
			mListeners.remove(l);
		}
	}
	
	/**
	 * get the message list of this target
	 * 
	 * @param target it means device ,broadcast or group 
	 * @return the message list of the target
	 */
	public ArrayList<MessageData> getMessage(SendTarget target)
	{

		if(mMessageMap.containsKey(target))
			return mMessageMap.get(target);
		
		return null;
	}

	/**
	 * get all devices of current WIFI
	 * 
	 * @return  all devices
	 */
	public ArrayList<Device> getDevices()
	{
		DeviceContext deviceContext = Controller.getInstance().getDeviceContext();
		return deviceContext.getDeviceList();
	}
	

	/**
	 * get all devices of group g
	 * 
	 * @param g group
	 * @return all devices in group g
	 */
	public ArrayList<Device> getDevices(Group g)
	{
		DeviceContext deviceContext = Controller.getInstance().getDeviceContext();
		return deviceContext.getDevicesInGroup(g.getGroupid());
	}
	
	/**
	 * get all group which current WIFI
	 * 
	 * @return all groups 
	 */
	public ArrayList<Group> getGroups()
	{
		DeviceContext deviceContext = Controller.getInstance().getDeviceContext();
		return deviceContext.getGroups();
	}

	/*public void addMessage(SendTarget key,SendTarget target, Object o,String path)
	{
		ArrayList<MessageData> messages = null;
		if(mMessageMap.containsKey(target))
		{
			messages = mMessageMap.get(target);
			messages.add((path == null) ? new MessageData(target,o) : new ImageMessageData(target,o,path));
			
		}
		else
		{
			messages = new ArrayList<MessageData>();
			messages.add((path == null) ? new MessageData(target,o) : new ImageMessageData(target,o,path));
			mMessageMap.put(target, messages);
		}
		notify(target,o);
	}
	*/
	public void addMessage(SendTarget key, SendTarget target,Object o,String path)
	{
		
		MessageData md = (path == null) ? new MessageData(key,target,o) : new ImageMessageData(key,target,o,path);
		if(mMessageMap.containsKey(key))
		{
			mMessageMap.get(key).add(md);
			
		}
		else
		{
			ArrayList<MessageData> groupMessage = new ArrayList<MessageData>();
			groupMessage.add(md);
			mMessageMap.put(key, groupMessage);
		}
		notify(target,o);
	}

	private void notify(SendTarget target, Object o)
	{
		
		for(WchatListener l : mListeners)
		{
			l.newMessage(target, o);
		}
	}
	
	private void notify(SendTarget target, boolean join)
	{
		
		for(WchatListener l : mListeners)
		{
			if(l instanceof DeviceAndGroupListener && ((target instanceof Group) || (target instanceof Device)))
			{
				if(join)
				{
					((DeviceAndGroupListener)l).Join(target);
				}
				else
				{
					((DeviceAndGroupListener)l).leave(target);
				}
			}
			
			
				
		}
	}

}
